package com.woniuxy.shiro.utils;

import com.woniuxy.entity.RbacManager;
import com.woniuxy.service.RbacManagerService;
import com.woniuxy.utils.JWTUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Set;

@Component//注册到spring容器中
public class MyRealmToken extends AuthorizingRealm {
    @Autowired
    RbacManagerService rbacManagerService;

    /**
     * shiro底层有过一个supports的方法，那个方法有问题，
     * 无法把我们自己写的MyJsonWebToken当做AuthenticationToken的实现类
     * MyJsonWebToken instenceof AuthenticationToken ===>false 所以我们要重写supports方法
     * @param token
     * @return
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof MyJsonWebToken;
    }
    /**
     * 授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//        System.out.println("您已进入权限判断，但是我啥都没写！");
        //当前有用户的权限进行判断
        String token = (String) principals.getPrimaryPrincipal();
        RbacManager rbacManager = rbacManagerService.findRbacManagerByTokenFromRedis(token);
        //可以通过rbacmanager::admin 当做key  角色权限数据都存redis中，如果redis中没有，就去数据库查询


        //通过这个对象，去数据库查出它所拥有的权限和角色 全部放入SET集合中
        int id = rbacManager.getId();
        Set<String> roles = rbacManagerService.findAllRolesById(id);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roles);
        //权限
        return simpleAuthorizationInfo;
    }

    /**
     * 认证：我们第一次登录不经过域
     * 第二次通过token登录认证的时候，先进入过滤器，然后我们才进入 自定义域 认证方法中
     * @param authenticationToken MyJsonWebToken  里面包含了token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        MyJsonWebToken myJsonWebToken = (MyJsonWebToken) authenticationToken;
        //通过校长获取 token
        String token = myJsonWebToken.getPrincipal()+"";
        //jwt工具类的方法，通过token获取用户名
        String userName = JWTUtil.getUserName(token);
        //判断userName是否是空的 如果有人修改过token
        if(userName==null){
            throw new AuthenticationException("token 无效");
        }
        //换成通过redis进行token认证，传入token，查出数据库的key，然后返回完整对象
        RbacManager rbacManager = rbacManagerService.findRbacManagerByTokenFromRedis(token);
        if (rbacManager != null){
            return new SimpleAuthenticationInfo(token, token, "MyRealmToken");
        }else{
            throw new AuthenticationException("账号或密码不匹配，token被篡改");
        }
    }
}
